package com.afdor.rws.dlock.zookeeper.aspect;

import com.afdor.rws.core.extension.ExtensionLoader;
import com.afdor.rws.dlock.annotation.DLock;
import com.afdor.rws.dlock.lock.ReentrantLock;
import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * 拦截DLock
 *
 * @author 悭梵
 * @date Created in 2018-09-03 16:29
 */
@Aspect
public class DLockAspect {

    @Resource
    private CuratorFramework curator;

    @Around("execution(public * *(..)) && (@within(com.afdor.rws.dlock.lock.annotation.DLock) || @annotation(com.afdor.rws.dlock.lock.annotation.DLock))")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature();
        if (signature instanceof MethodSignature) {
            Object[] args = joinPoint.getArgs();
            Object target = joinPoint.getTarget();
            Method targetMethod = ((MethodSignature) signature).getMethod();

            DLock dLock = targetMethod.getAnnotation(DLock.class);

            StringBuilder __DLockId = new StringBuilder(100);
            String lockId = dLock.name();
            if (StringUtils.isBlank(lockId)) {
                __DLockId.append(target.getClass().getName()).append(".").append(targetMethod.getName());
            } else {
                __DLockId.append(lockId);
            }

            String[] subKeys = dLock.subKeys();
            if (subKeys != null && subKeys.length > 0) {
                __DLockId.append("?");
                for (String subKey : subKeys) {
                    __DLockId.append(subKey).append("&");
                }
            }

            ReentrantLock lock = null;

            try {
                lock = ExtensionLoader
                        .getInstance(ReentrantLock.class)
                        .newExtensionOrDefault(dLock.lockExtensionName(), curator, __DLockId);

                lock.lock();

                return joinPoint.proceed();
            } catch (Throwable t) {
                throw t;
            } finally {
                if (lock != null) {
                    lock.unlock();
                }
            }
        } else {
            try {
                return joinPoint.proceed();
            } catch (Throwable t) {
                throw t;
            }
        }
    }
}
